import json
import tkinter as tk
from tkinter import ttk, messagebox, Canvas, Frame, simpledialog
from PIL import Image, ImageTk, ImageGrab
import base64
import requests
import io
import threading

# 导入日志配置
from log_config import logger
from config import settings

# 默认配置
DEFAULT_SETTINGS = {
    "version_api_key": settings.version_api_key,
    "version_base_url": settings.version_base_url,
    "version_model": settings.version_model,
    "thinking_api_key": settings.thinking_api_key,
    "thinking_base_url": settings.thinking_base_url,
    "thinking_model": settings.thinking_model,
    "llm_base_url": settings.llm_base_url,
    "llm_model": settings.llm_model,
    "llm_api_key": settings.llm_api_key,
    "screenshot_border_size": settings.screenshot_border_size,
    "screenshot_border_color": settings.screenshot_border_color
}

OCR_PROMPT = """
分析图片，提取图片内容，整理成json格式。
请注意只返回json内容即可，并以<question></question>标签包裹。
参考格式如下：
<question>
{
    "is_question": "true",
    "knowledge_type": "函数",
    "question_type": "选择题",
    "content": "函数图像是y=2x+1，函数解析式是y=2x+1，函数的零点是(-1,1)，函数的图象上的点(-1,1)的切线斜率是2。",
}
</question>
"""

THINKING_PROMPT = """
你是一位数学解题高手，
请仔细分析题目内容，思考解题步骤。按照以下步骤执行。
1、先按照题目内容生成相应的 Geogebra 绘图指令，并补充其他解题必要的辅助线。
2、除了生成题目内容的 Geogebra 绘图指令外，如果是选择题请给每个选项生成需要的 
Geogebra 指令，如果是解答题并且分小题的，按照小题生成 Geogebra 指令。
3、必须反思Geogebra是否存在每个指令，并且使用是否正确。
"""

GEN_HTML_PROMPT = """
#角色
你是一位 GeoGebra 画图专家
•   精通GeoGebra的2D/3D图形绘制
•   熟悉GeoGebra JavaScript API（ggbApp操作）
•   能够通过HTML/CSS/JS实现交互式绘图界面

功能需求
1. HTML页面结构
•   头部：
•   左侧：GeoGebra绘图区域（固定尺寸，非100%）
•   右侧：控制面板（包含按钮和输入框）
2. GeoGebra初始化
•   使用官方CDN引入deployggb.js
•   初始化参数参考：
var parameters = { "id": "ggbApplet", "appName": "classic", "width": "600", "height": "500", "showMenuBar": true, "showAlgebraInput": true, "showToolBar": true, "showToolBarHelp": true, "showResetIcon": true, "enableLabelDrags": true, "enableShiftDragZoom": true, "enableRightClick": true, "errorDialogsActive": false, "useBrowserForJS": false, "allowStyleBar": false, "preventFocus": false, "showZoomButtons": true, "capturingThreshold": 3, "showFullscreenButton": true, "scale": 1, "disableAutoScale": false, "allowUpscale": false, "clickToLoad": false, "buttonRounding": 0.7, "buttonShadows": false, "language": "zh-CN", "appletOnLoad": function(api) { window.ggbApp = api;  } };

限制条件：
3. 重置图表使用window.ggbApp.reset()
4. 初始化参数中不要使用materialid， filename，base64
5. 不要设置全局变量ggbApp，只在appletOnLoad 中设置 window.ggbApp = api，后续都使用ggbApp操作Geogebra 的 API
6. GeoGebra 命令执行使用ggbApp.evalCommand('')方法，单个命令执行，命令不使用中文名称，记住要思考每个命令是否存在，使用方式是否正确。
7. 兼容性
•   支持现代浏览器（Chrome/Firefox/Edge）
•   绘图区域尺寸必须为固定值（如800x600），parameters参数中的width和height不要修改，绝对不能改成100%。
Geogebra大小自适应窗口大小，参考如下代码调整GeoGebra应用大小 function resizeApplet() { const container = document.querySelector('.ggb-container'); const width = container.offsetWidth; const height = container.offsetHeight; // 如果应用已加载，强制重绘 if (ggbApp && typeof ggbApp.recalculateEnvironments === 'function') { ggbApp.setSize(width, height); } }
•   页面样式和字体使用font-awesome和google-fonts

输出要求
•   提供完整的HTML文件，包含内联CSS和JS
•   代码注释关键步骤（如GeoGebra初始化、图形生成逻辑）

请按照上面生成的 Geogebra指令生成html演示课件。如果是选择题请给每个选项生成一个操作按钮，点击按钮显示GeoGebra绘图内容，并在切换选项时可以全部删除之前选项生成的内容。如果是解答题并且分小题的，请给每个小题生成一个操作按钮，点击按钮显示GeoGebra绘图内容，并在切换小题时可以全部删除之前选项生成的内容。点击不同按钮显示相应的解题思路。

请按照上面生成的 Geogebra指令生成html演示课件。
要求：
1、如果是选择题请给每个选项生成一个操作按钮，点击按钮显示GeoGebra绘图内容，并在切换选项时可以全部删除之前选项生成的内容。
2、如果是解答题并且分小题的，请给每个小题生成一个操作按钮，点击按钮显示GeoGebra绘图内容，并在切换小题时可以全部删除之前选项生成的内容。
3、点击不同按钮显示相应的解题思路。
4、如果Geogebra指令有错误，请直接修改。
"""

class TaskThread(threading.Thread):
    def __init__(self, image, settings, callback):
        super().__init__()
        self.image = image
        self.settings = settings
        self.callback = callback
        self.error = None
    def send_ocr_request(self, model, base_url, api_key, base64_image):
        """
        发送API请求以分析图片。

        :param base64_image: 经过Base64编码的图片数据
        :return: API响应中的结果文本
        """
        # 准备API请求
        headers = {
            "Content-Type": "application/json",
            "Authorization": f"Bearer {api_key}",
        }

        # 创建请求体
        payload = {
            "model": model,
            "messages": [
                {
                    "role": "system",
                    "content": [
                        {
                            "type": "text",
                            "text": OCR_PROMPT
                        }
                    ]
                },
                {
                    "role": "user",
                    "content": [
                        {
                            "type": "image_url",
                            "image_url": {
                                "url": f"data:image/png;base64,{base64_image}"
                            }
                        }
                    ]
                }
            ],
            "max_tokens": 8000
        }

        logger.info(f"开始发送OCR API请求，模型: {model}, 基础URL: {base_url}")
        try:
            # 发送API请求
            response = requests.post(
                base_url, 
                headers=headers, 
                json=payload
            )
            response.raise_for_status()
            logger.info("OCR API请求成功")
        except Exception as e:
            logger.error(f"OCR API请求失败: {e}")
            raise
        
        # 解析响应
        data = response.json()
        return data["choices"][0]["message"]["content"]

    def send_thinking_request(self, model, base_url, api_key, user_input):
        """
        发送API请求以分析题目并生成Geogebra指令。

        :param user_input: 题目内容
        :return: API响应中的结果文本
        """
        # 准备API请求
        headers = {
            "Content-Type": "application/json",
            "Authorization": f"Bearer {api_key}",
        }

        # 创建请求体
        payload = {
            "model": model,
            "messages": [
                {
                    "role": "system",
                    "content": [
                        {
                            "type": "text",
                            "text": THINKING_PROMPT
                        }
                    ]
                },
                {
                    "role": "user",
                    "content": [
                        {
                            "type": "text",
                            "text": user_input
                        }
                    ]
                }
            ],
            # "max_tokens": 8000
        }

        logger.info(f"开始发送OCR API请求，模型: {model}, 基础URL: {base_url}")
        try:
            # 发送API请求
            response = requests.post(
                base_url, 
                headers=headers, 
                json=payload
            )
            response.raise_for_status()
            logger.info("OCR API请求成功")
        except Exception as e:
            logger.error(f"OCR API请求失败: {e}")
            raise
        
        # 解析响应
        data = response.json()
        return data["choices"][0]["message"]["content"]

    def generate_html(self, model, base_url, api_key, user_input):
        """
        生成HTML演示课件的API请求并获取响应结果。

        :param result_text: 分析图片生成的Geogebra指令文本
        :return: API响应中的HTML内容
        """
        # 准备API请求
        headers = {
            "Content-Type": "application/json",
            "Authorization": f"Bearer {api_key}",
        }

        # 创建请求体
        payload = {
            "model": model,
            "messages": [
                {
                    "role": "system",
                    "content": [
                        {
                            "type": "text",
                            "text": GEN_HTML_PROMPT
                        }
                    ]
                },
                {
                    "role": "user",
                    "content": [
                        {
                            "type": "text",
                            "text": user_input
                        }
                    ]
                }
            ]
        }
        
        logger.info(f"开始发送生成HTML API请求，模型: {model}, 基础URL: {base_url}")
        try:
            # 发送API请求
            response = requests.post(
                base_url, 
                headers=headers, 
                json=payload
            )
            response.raise_for_status()
            logger.info("生成HTML API请求成功")
        except Exception as e:
            logger.error(f"生成HTML API请求失败: {e}")
            raise
        
        # 解析响应
        data = response.json()
        return data["choices"][0]["message"]["content"]


    def run(self):
        """执行任务"""
        try:
            logger.info("开始执行OCR任务")
            # 将图像转换为字节流
            buffered = io.BytesIO()
            self.image.save(buffered, format="PNG")
            img_data = buffered.getvalue()
            
            # 将图像转换为Base64
            base64_image = base64.b64encode(img_data).decode('utf-8')
            
            # 调用封装方法发送请求
            result_text = self.send_ocr_request(self.settings['version_model'], self.settings['version_base_url'], self.settings['version_api_key'], base64_image)
            if "<question>" not in result_text or "</question>" not in result_text:
                logger.error("OCR结果格式错误")
                self.callback(None)
                return
            # 提取json内容
            json_str = result_text.split("<question>")[1].split("</question>")[0]
            json_data = json.loads(json_str)
            json_data["question"] = json_data["question"].replace("\n", "")
            
            if not json_data["is_question"]:
                raise Exception("上传图片不包含题目")
            
            # 调用封装方法发送请求
            result_text = self.send_thinking_request(self.settings['thinking_model'], self.settings['thinking_base_url'], self.settings['thinking_api_key'], json_str)
            
            # 调用封装方法生成 HTML
            result_text = self.generate_html(self.settings['llm_model'], self.settings['llm_base_url'], self.settings['llm_api_key'], result_text)
            
            # 回调主线程
            self.callback(result_text)
            logger.info("任务执行成功")
        
        except Exception as e:
            self.error = str(e)
            self.callback(None)
            logger.error(f"任务执行失败: {e}")

 

def handle_result(self, result):
    """处理结果"""
    if result:
        logger.info("开始提取HTML内容并保存")
        try:
            # 提取 html 内容
            html_content = result.split("```html")[1].split("```")[0]
            # 保存到文件 
            with open("output.html", "w", encoding="utf-8") as file:
                file.write(html_content)
            logger.info("HTML内容保存成功")
        except Exception as e:
            logger.error(f"提取或保存HTML内容失败: {e}")
    else:
        logger.warning("生成内容为空")
        print("生成内容为空")

if __name__ == "__main__":
     # 在新线程中执行OCR
    #  读取图片
    path = "image.png"
    # 添加切题流程
    
    current_screenshot = Image.open(path)
    logger.info("开始执行主程序，读取图片")
    ocr_thread = TaskThread(
        current_screenshot,
        DEFAULT_SETTINGS,
        handle_result
    )
    ocr_thread.start()